// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/feature_list.h"

#include <stddef.h>

#include <algorithm>
#include <utility>

#include "base/format_macros.h"
#include "base/macros.h"
#include "base/memory/ptr_util.h"
#include "base/metrics/field_trial.h"
#include "base/metrics/persistent_memory_allocator.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace base {

namespace {

    const char kFeatureOnByDefaultName[] = "OnByDefault";
    struct Feature kFeatureOnByDefault {
        kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
    };

    const char kFeatureOffByDefaultName[] = "OffByDefault";
    struct Feature kFeatureOffByDefault {
        kFeatureOffByDefaultName, FEATURE_DISABLED_BY_DEFAULT
    };

    std::string SortFeatureListString(const std::string& feature_list)
    {
        std::vector<std::string> features = FeatureList::SplitFeatureListString(feature_list);
        std::sort(features.begin(), features.end());
        return JoinString(features, ",");
    }

} // namespace

class FeatureListTest : public testing::Test {
public:
    FeatureListTest()
        : feature_list_(nullptr)
    {
        RegisterFeatureListInstance(WrapUnique(new FeatureList));
    }
    ~FeatureListTest() override { ClearFeatureListInstance(); }

    void RegisterFeatureListInstance(std::unique_ptr<FeatureList> feature_list)
    {
        FeatureList::ClearInstanceForTesting();
        feature_list_ = feature_list.get();
        FeatureList::SetInstance(std::move(feature_list));
    }
    void ClearFeatureListInstance()
    {
        FeatureList::ClearInstanceForTesting();
        feature_list_ = nullptr;
    }

    FeatureList* feature_list() { return feature_list_; }

private:
    // Weak. Owned by the FeatureList::SetInstance().
    FeatureList* feature_list_;

    DISALLOW_COPY_AND_ASSIGN(FeatureListTest);
};

TEST_F(FeatureListTest, DefaultStates)
{
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
}

TEST_F(FeatureListTest, InitializeFromCommandLine)
{
    struct {
        const char* enable_features;
        const char* disable_features;
        bool expected_feature_on_state;
        bool expected_feature_off_state;
    } test_cases[] = {
        { "", "", true, false },
        { "OffByDefault", "", true, true },
        { "OffByDefault", "OnByDefault", false, true },
        { "OnByDefault,OffByDefault", "", true, true },
        { "", "OnByDefault,OffByDefault", false, false },
        // In the case an entry is both, disable takes precedence.
        { "OnByDefault", "OnByDefault,OffByDefault", false, false },
    };

    for (size_t i = 0; i < arraysize(test_cases); ++i) {
        const auto& test_case = test_cases[i];
        SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
            test_case.enable_features,
            test_case.disable_features));

        ClearFeatureListInstance();
        std::unique_ptr<FeatureList> feature_list(new FeatureList);
        feature_list->InitializeFromCommandLine(test_case.enable_features,
            test_case.disable_features);
        RegisterFeatureListInstance(std::move(feature_list));

        EXPECT_EQ(test_case.expected_feature_on_state,
            FeatureList::IsEnabled(kFeatureOnByDefault))
            << i;
        EXPECT_EQ(test_case.expected_feature_off_state,
            FeatureList::IsEnabled(kFeatureOffByDefault))
            << i;
    }
}

TEST_F(FeatureListTest, CheckFeatureIdentity)
{
    // Tests that CheckFeatureIdentity() correctly detects when two different
    // structs with the same feature name are passed to it.

    // Call it twice for each feature at the top of the file, since the first call
    // makes it remember the entry and the second call will verify it.
    EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault));
    EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault));
    EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault));
    EXPECT_TRUE(feature_list()->CheckFeatureIdentity(kFeatureOffByDefault));

    // Now, call it with a distinct struct for |kFeatureOnByDefaultName|, which
    // should return false.
    struct Feature kFeatureOnByDefault2 {
        kFeatureOnByDefaultName, FEATURE_ENABLED_BY_DEFAULT
    };
    EXPECT_FALSE(feature_list()->CheckFeatureIdentity(kFeatureOnByDefault2));
}

TEST_F(FeatureListTest, FieldTrialOverrides)
{
    struct {
        FeatureList::OverrideState trial1_state;
        FeatureList::OverrideState trial2_state;
    } test_cases[] = {
        { FeatureList::OVERRIDE_DISABLE_FEATURE,
            FeatureList::OVERRIDE_DISABLE_FEATURE },
        { FeatureList::OVERRIDE_DISABLE_FEATURE,
            FeatureList::OVERRIDE_ENABLE_FEATURE },
        { FeatureList::OVERRIDE_ENABLE_FEATURE,
            FeatureList::OVERRIDE_DISABLE_FEATURE },
        { FeatureList::OVERRIDE_ENABLE_FEATURE,
            FeatureList::OVERRIDE_ENABLE_FEATURE },
    };

    FieldTrial::ActiveGroup active_group;
    for (size_t i = 0; i < arraysize(test_cases); ++i) {
        const auto& test_case = test_cases[i];
        SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]", i));

        ClearFeatureListInstance();

        FieldTrialList field_trial_list(nullptr);
        std::unique_ptr<FeatureList> feature_list(new FeatureList);

        FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
        FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
        feature_list->RegisterFieldTrialOverride(kFeatureOnByDefaultName,
            test_case.trial1_state, trial1);
        feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
            test_case.trial2_state, trial2);
        RegisterFeatureListInstance(std::move(feature_list));

        // Initially, neither trial should be active.
        EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
        EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));

        const bool expected_enabled_1 = (test_case.trial1_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
        EXPECT_EQ(expected_enabled_1, FeatureList::IsEnabled(kFeatureOnByDefault));
        // The above should have activated |trial1|.
        EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
        EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));

        const bool expected_enabled_2 = (test_case.trial2_state == FeatureList::OVERRIDE_ENABLE_FEATURE);
        EXPECT_EQ(expected_enabled_2, FeatureList::IsEnabled(kFeatureOffByDefault));
        // The above should have activated |trial2|.
        EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
        EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
    }
}

TEST_F(FeatureListTest, FieldTrialAssociateUseDefault)
{
    FieldTrialList field_trial_list(nullptr);
    std::unique_ptr<FeatureList> feature_list(new FeatureList);

    FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
    FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
    feature_list->RegisterFieldTrialOverride(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
    feature_list->RegisterFieldTrialOverride(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
    RegisterFeatureListInstance(std::move(feature_list));

    // Initially, neither trial should be active.
    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial1->trial_name()));
    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));

    // Check the feature enabled state is its default.
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
    // The above should have activated |trial1|.
    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial2->trial_name()));

    // Check the feature enabled state is its default.
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
    // The above should have activated |trial2|.
    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial1->trial_name()));
    EXPECT_TRUE(FieldTrialList::IsTrialActive(trial2->trial_name()));
}

TEST_F(FeatureListTest, CommandLineTakesPrecedenceOverFieldTrial)
{
    ClearFeatureListInstance();

    FieldTrialList field_trial_list(nullptr);
    std::unique_ptr<FeatureList> feature_list(new FeatureList);

    // The feature is explicitly enabled on the command-line.
    feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");

    // But the FieldTrial would set the feature to disabled.
    FieldTrial* trial = FieldTrialList::CreateFieldTrial("TrialExample2", "A");
    feature_list->RegisterFieldTrialOverride(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, trial);
    RegisterFeatureListInstance(std::move(feature_list));

    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
    // Command-line should take precedence.
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
    // Since the feature is on due to the command-line, and not as a result of the
    // field trial, the field trial should not be activated (since the Associate*
    // API wasn't used.)
    EXPECT_FALSE(FieldTrialList::IsTrialActive(trial->trial_name()));
}

TEST_F(FeatureListTest, IsFeatureOverriddenFromCommandLine)
{
    ClearFeatureListInstance();

    FieldTrialList field_trial_list(nullptr);
    std::unique_ptr<FeatureList> feature_list(new FeatureList);

    // No features are overridden from the command line yet
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));

    // Now, enable |kFeatureOffByDefaultName| via the command-line.
    feature_list->InitializeFromCommandLine(kFeatureOffByDefaultName, "");

    // It should now be overridden for the enabled group.
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
    EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));

    // Register a field trial to associate with the feature and ensure that the
    // results are still the same.
    feature_list->AssociateReportingFieldTrial(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
        FieldTrialList::CreateFieldTrial("Trial1", "A"));
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
    EXPECT_TRUE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));

    // Now, register a field trial to override |kFeatureOnByDefaultName| state
    // and check that the function still returns false for that feature.
    feature_list->RegisterFieldTrialOverride(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
        FieldTrialList::CreateFieldTrial("Trial2", "A"));
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
    EXPECT_FALSE(feature_list->IsFeatureOverriddenFromCommandLine(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
    RegisterFeatureListInstance(std::move(feature_list));

    // Check the expected feature states for good measure.
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
}

TEST_F(FeatureListTest, AssociateReportingFieldTrial)
{
    struct {
        const char* enable_features;
        const char* disable_features;
        bool expected_enable_trial_created;
        bool expected_disable_trial_created;
    } test_cases[] = {
        // If no enable/disable flags are specified, no trials should be created.
        { "", "", false, false },
        // Enabling the feature should result in the enable trial created.
        { kFeatureOffByDefaultName, "", true, false },
        // Disabling the feature should result in the disable trial created.
        { "", kFeatureOffByDefaultName, false, true },
    };

    const char kTrialName[] = "ForcingTrial";
    const char kForcedOnGroupName[] = "ForcedOn";
    const char kForcedOffGroupName[] = "ForcedOff";

    for (size_t i = 0; i < arraysize(test_cases); ++i) {
        const auto& test_case = test_cases[i];
        SCOPED_TRACE(base::StringPrintf("Test[%" PRIuS "]: [%s] [%s]", i,
            test_case.enable_features,
            test_case.disable_features));

        ClearFeatureListInstance();

        FieldTrialList field_trial_list(nullptr);
        std::unique_ptr<FeatureList> feature_list(new FeatureList);
        feature_list->InitializeFromCommandLine(test_case.enable_features,
            test_case.disable_features);

        FieldTrial* enable_trial = nullptr;
        if (feature_list->IsFeatureOverriddenFromCommandLine(
                kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE)) {
            enable_trial = base::FieldTrialList::CreateFieldTrial(kTrialName,
                kForcedOnGroupName);
            feature_list->AssociateReportingFieldTrial(
                kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE,
                enable_trial);
        }
        FieldTrial* disable_trial = nullptr;
        if (feature_list->IsFeatureOverriddenFromCommandLine(
                kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE)) {
            disable_trial = base::FieldTrialList::CreateFieldTrial(
                kTrialName, kForcedOffGroupName);
            feature_list->AssociateReportingFieldTrial(
                kFeatureOffByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE,
                disable_trial);
        }
        EXPECT_EQ(test_case.expected_enable_trial_created, enable_trial != nullptr);
        EXPECT_EQ(test_case.expected_disable_trial_created,
            disable_trial != nullptr);
        RegisterFeatureListInstance(std::move(feature_list));

        EXPECT_FALSE(FieldTrialList::IsTrialActive(kTrialName));
        if (disable_trial) {
            EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
            EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
            EXPECT_EQ(kForcedOffGroupName, disable_trial->group_name());
        } else if (enable_trial) {
            EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
            EXPECT_TRUE(FieldTrialList::IsTrialActive(kTrialName));
            EXPECT_EQ(kForcedOnGroupName, enable_trial->group_name());
        }
    }
}

TEST_F(FeatureListTest, GetFeatureOverrides)
{
    ClearFeatureListInstance();
    FieldTrialList field_trial_list(nullptr);
    std::unique_ptr<FeatureList> feature_list(new FeatureList);
    feature_list->InitializeFromCommandLine("A,X", "D");

    FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
    feature_list->RegisterFieldTrialOverride(kFeatureOffByDefaultName,
        FeatureList::OVERRIDE_ENABLE_FEATURE,
        trial);

    RegisterFeatureListInstance(std::move(feature_list));

    std::string enable_features;
    std::string disable_features;
    FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
        &disable_features);
    EXPECT_EQ("A,OffByDefault<Trial,X", SortFeatureListString(enable_features));
    EXPECT_EQ("D", SortFeatureListString(disable_features));
}

TEST_F(FeatureListTest, GetFeatureOverrides_UseDefault)
{
    ClearFeatureListInstance();
    FieldTrialList field_trial_list(nullptr);
    std::unique_ptr<FeatureList> feature_list(new FeatureList);
    feature_list->InitializeFromCommandLine("A,X", "D");

    FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
    feature_list->RegisterFieldTrialOverride(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);

    RegisterFeatureListInstance(std::move(feature_list));

    std::string enable_features;
    std::string disable_features;
    FeatureList::GetInstance()->GetFeatureOverrides(&enable_features,
        &disable_features);
    EXPECT_EQ("*OffByDefault<Trial,A,X", SortFeatureListString(enable_features));
    EXPECT_EQ("D", SortFeatureListString(disable_features));
}

TEST_F(FeatureListTest, GetFieldTrial)
{
    ClearFeatureListInstance();
    FieldTrialList field_trial_list(nullptr);
    FieldTrial* trial = FieldTrialList::CreateFieldTrial("Trial", "Group");
    std::unique_ptr<FeatureList> feature_list(new FeatureList);
    feature_list->RegisterFieldTrialOverride(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial);
    RegisterFeatureListInstance(std::move(feature_list));

    EXPECT_EQ(trial, FeatureList::GetFieldTrial(kFeatureOnByDefault));
    EXPECT_EQ(nullptr, FeatureList::GetFieldTrial(kFeatureOffByDefault));
}

TEST_F(FeatureListTest, InitializeFromCommandLine_WithFieldTrials)
{
    ClearFeatureListInstance();
    FieldTrialList field_trial_list(nullptr);
    FieldTrialList::CreateFieldTrial("Trial", "Group");
    std::unique_ptr<FeatureList> feature_list(new FeatureList);
    feature_list->InitializeFromCommandLine("A,OffByDefault<Trial,X", "D");
    RegisterFeatureListInstance(std::move(feature_list));

    EXPECT_FALSE(FieldTrialList::IsTrialActive("Trial"));
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOffByDefault));
    EXPECT_TRUE(FieldTrialList::IsTrialActive("Trial"));
}

TEST_F(FeatureListTest, InitializeFromCommandLine_UseDefault)
{
    ClearFeatureListInstance();
    FieldTrialList field_trial_list(nullptr);
    FieldTrialList::CreateFieldTrial("T1", "Group");
    FieldTrialList::CreateFieldTrial("T2", "Group");
    std::unique_ptr<FeatureList> feature_list(new FeatureList);
    feature_list->InitializeFromCommandLine(
        "A,*OffByDefault<T1,*OnByDefault<T2,X", "D");
    RegisterFeatureListInstance(std::move(feature_list));

    EXPECT_FALSE(FieldTrialList::IsTrialActive("T1"));
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
    EXPECT_TRUE(FieldTrialList::IsTrialActive("T1"));

    EXPECT_FALSE(FieldTrialList::IsTrialActive("T2"));
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
    EXPECT_TRUE(FieldTrialList::IsTrialActive("T2"));
}

TEST_F(FeatureListTest, InitializeInstance)
{
    ClearFeatureListInstance();

    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);
    FeatureList::SetInstance(std::move(feature_list));
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));

    // Initialize from command line if we haven't yet.
    FeatureList::InitializeInstance("", kFeatureOnByDefaultName);
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));

    // Do not initialize from commandline if we have already.
    FeatureList::InitializeInstance(kFeatureOffByDefaultName, "");
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOnByDefault));
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
}

TEST_F(FeatureListTest, UninitializedInstance_IsEnabledReturnsFalse)
{
    ClearFeatureListInstance();
    // This test case simulates the calling pattern found in code which does not
    // explicitly initialize the features list.
    // All IsEnabled() calls should return the default value in this scenario.
    EXPECT_EQ(nullptr, FeatureList::GetInstance());
    EXPECT_TRUE(FeatureList::IsEnabled(kFeatureOnByDefault));
    EXPECT_EQ(nullptr, FeatureList::GetInstance());
    EXPECT_FALSE(FeatureList::IsEnabled(kFeatureOffByDefault));
}

TEST_F(FeatureListTest, StoreAndRetrieveFeaturesFromSharedMemory)
{
    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);

    // Create some overrides.
    feature_list->RegisterOverride(kFeatureOffByDefaultName,
        FeatureList::OVERRIDE_ENABLE_FEATURE, nullptr);
    feature_list->RegisterOverride(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE, nullptr);
    feature_list->FinalizeInitialization();

    // Create an allocator and store the overrides.
    std::unique_ptr<SharedMemory> shm(new SharedMemory());
    shm->CreateAndMapAnonymous(4 << 10);
    SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false);
    feature_list->AddFeaturesToAllocator(&allocator);

    std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);

    // Check that the new feature list is empty.
    EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
    EXPECT_FALSE(feature_list2->IsFeatureOverriddenFromCommandLine(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));

    feature_list2->InitializeFromSharedMemory(&allocator);
    // Check that the new feature list now has 2 overrides.
    EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_ENABLE_FEATURE));
    EXPECT_TRUE(feature_list2->IsFeatureOverriddenFromCommandLine(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_DISABLE_FEATURE));
}

TEST_F(FeatureListTest, StoreAndRetrieveAssociatedFeaturesFromSharedMemory)
{
    FieldTrialList field_trial_list(nullptr);
    std::unique_ptr<base::FeatureList> feature_list(new base::FeatureList);

    // Create some overrides.
    FieldTrial* trial1 = FieldTrialList::CreateFieldTrial("TrialExample1", "A");
    FieldTrial* trial2 = FieldTrialList::CreateFieldTrial("TrialExample2", "B");
    feature_list->RegisterFieldTrialOverride(
        kFeatureOnByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial1);
    feature_list->RegisterFieldTrialOverride(
        kFeatureOffByDefaultName, FeatureList::OVERRIDE_USE_DEFAULT, trial2);
    feature_list->FinalizeInitialization();

    // Create an allocator and store the overrides.
    std::unique_ptr<SharedMemory> shm(new SharedMemory());
    shm->CreateAndMapAnonymous(4 << 10);
    SharedPersistentMemoryAllocator allocator(std::move(shm), 1, "", false);
    feature_list->AddFeaturesToAllocator(&allocator);

    std::unique_ptr<base::FeatureList> feature_list2(new base::FeatureList);
    feature_list2->InitializeFromSharedMemory(&allocator);
    feature_list2->FinalizeInitialization();

    // Check that the field trials are still associated.
    FieldTrial* associated_trial1 = feature_list2->GetAssociatedFieldTrial(kFeatureOnByDefault);
    FieldTrial* associated_trial2 = feature_list2->GetAssociatedFieldTrial(kFeatureOffByDefault);
    EXPECT_EQ(associated_trial1, trial1);
    EXPECT_EQ(associated_trial2, trial2);
}

} // namespace base
